﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace GameJam2012
{
    public class PlayerEntity : Entity
    {
        Vector2 velocity = Vector2.Zero;
        float airMove = .75f;
        Vector2 bounceDampening = new Vector2(.5f, 0f);
        Vector2 maxVelocity = new Vector2(15f, 10f);
        Vector2 minVelocity = new Vector2(.5f, 0f);
        float idleRollSpeed = .05f;
        float groundFriction = .97f;
        float acceleration = .5f;
        float jumpAcceleration = 10f;
        double jumpTime = 110;
        double timeSinceJump = 0;
        double timeSinceGround = 0;
        double jumpWindow = 75;
        bool onGround = false;
        bool canJump = false;
        float radius = 32f;
        float angle = 0f;
        float halfHitboxWidth { get { return 48 * size; } }
        float halfHitboxHeight { get { return 60 * size; } }
        double lastJumpPress = 1000;

        float size = .5f;
        float rateOfShrinkage = -.0007f;
        float foodRecharge = .25f;
        float minSize = .1f;
        float damageShrinking = -.01f;

        double distanceMoved = 0;

        double killCountdown = 5000;
        bool dying = false;

        public PlayerEntity()
            : base()
        {
            Position = new Vector2(128, 256);
        }

        public void Spawn(Level level)
        {
            if (level.SpawnPoint != null) Position = (Vector2)level.SpawnPoint;
            SnakeGame.EATING.Play();
        }

        public override void Update(GameTime gameTime, Level level)
        {
            base.Update(gameTime, level);

            if (dying)
            {
                killCountdown -= gameTime.ElapsedGameTime.TotalMilliseconds;
                if (killCountdown <= 0)
                {
                    Dead = true;

                }
                return;
            }

            size += rateOfShrinkage;
            if (size <= minSize)
            {
                level.ps.Gush(Position);
                SnakeGame.EATMEAT.Play(1f, 0f, 0f);
                Kill();
            }

            bool moving = false;

            velocity += Level.Gravity;
            KeyboardState kb = Keyboard.GetState();
            if (kb.IsKeyDown(Keys.G)){// && prevKeyboardState.IsKeyUp(Keys.G)) {
                float gushPostion = Position.X;/*
                if (level.LeftBound < 250.0f || true) {
                    gushPostion -= level.LeftBound;
                } else {
                    gushPostion +=  level.LeftBound;
                }*/
                level.ps.Gush(new Vector2 (gushPostion,Position.Y));
            }

            if (kb.IsKeyDown(Keys.A) || kb.IsKeyDown(Keys.Left))
            {
                velocity.X -= (onGround ? 1f : airMove) * acceleration;
                moving = true;
            }
            if (kb.IsKeyDown(Keys.D) || kb.IsKeyDown(Keys.Right))
            {
                moving = true;
                velocity.X += (onGround ? 1f : airMove) * acceleration;
            }
            if (kb.IsKeyDown(Keys.S))
            {
                //velocity.Y += acceleration;
            }
            
            if (kb.IsKeyDown(Keys.W) || kb.IsKeyDown(Keys.Up))
            {
                lastJumpPress = 0;
            }
            if(lastJumpPress <= jumpWindow)
            {
                if (canJump)
                {
                    canJump = false;
                    timeSinceJump = 0;
                    velocity.Y -= jumpAcceleration;
                    SnakeGame.JUMPING.Play();
                }
                else if (timeSinceJump <= jumpTime)
                {
                    velocity.Y -= jumpAcceleration;
                }
            }
            else if (onGround)
            {
                // Handle minimum velocity
                if (!moving)
                {
                    if (Math.Abs(velocity.X) < minVelocity.X)
                    {
                        if (velocity.X < 0)
                        {
                            velocity.X -= idleRollSpeed;
                        }
                        else
                        {
                            velocity.X += idleRollSpeed;
                        }
                    }
                }
                canJump = true;
                timeSinceGround = 0;
                timeSinceJump = 0;
            }
            lastJumpPress += gameTime.ElapsedGameTime.TotalMilliseconds;
            timeSinceGround += gameTime.ElapsedGameTime.TotalMilliseconds;
            timeSinceJump += gameTime.ElapsedGameTime.TotalMilliseconds;
            if (timeSinceGround > jumpWindow)
                canJump = false;
            onGround = false;

            velocity.X = Math.Max(-maxVelocity.X, Math.Min(maxVelocity.X, velocity.X));
            velocity.Y = Math.Max(-maxVelocity.Y, Math.Min(maxVelocity.Y, velocity.Y));

            if (!Keyboard.GetState().IsKeyDown(Keys.LeftShift))
            {
                FloatRectangle boundX = new FloatRectangle(Position.X + velocity.X - halfHitboxWidth, Position.Y - halfHitboxHeight, halfHitboxWidth * 2, halfHitboxHeight * 2);
                FloatRectangle boundY = new FloatRectangle(Position.X - halfHitboxWidth, Position.Y + velocity.Y - halfHitboxHeight, halfHitboxWidth * 2, halfHitboxHeight * 2);
                Collision colX = level.CheckWorldCollision(boundX, true, true);
                Collision colY = level.CheckWorldCollision(boundY, true, true);
                if (colX == null)
                {
                    Position.X += velocity.X;
                    if (velocity.X > 0)
                        distanceMoved += velocity.X / SnakeGame.TILESIZE;
                }
                else
                {
                    // adjust for X direction collision by snapping to the collision point
                    if (velocity.X > 0)
                    {
                        Position.X += colX.CollisionRectangle.Left - Position.X - halfHitboxWidth; 
                    }
                    else if (velocity.X < 0)
                    {
                        Position.X -= Position.X - halfHitboxWidth - colX.CollisionRectangle.Right;
                    }
                    if (Math.Abs(velocity.X) > 2) SnakeGame.LANDING.Play();
                    velocity.X = -velocity.X * bounceDampening.X;
                }
                if (colY == null)
                {
                    Position.Y += velocity.Y;
                }
                else
                {
                    // adjust for Y direction collision by snapping to collision point
                    if (velocity.Y > 0)
                    {
                        //Position.Y += colY.CollisionRectangle.Top - (Position.Y + 33f);
                        Position.Y = colY.CollisionRectangle.Top - halfHitboxHeight;
                        velocity.X *= groundFriction;
                        onGround = true;
                    }
                    else if (velocity.Y < 0)
                    {
                        Position.Y -= (Position.Y - halfHitboxHeight) - colY.CollisionRectangle.Bottom;
                    }
                    if (Math.Abs(velocity.Y) > 2) SnakeGame.LANDING.Play();
                    velocity.Y = -velocity.Y * bounceDampening.Y;
                    
                }
            }
            else
                Position += velocity;

            float angleVelocity = velocity.X / radius;
            angle += angleVelocity;
        }

        public override void Draw(SpriteBatch spriteBatch, float xOffset, float yOffset, Color tint)
        {
            
            base.Draw(spriteBatch, xOffset, yOffset, tint);

            spriteBatch.DrawString(SnakeGame.FONT, "HIGH SCORE: " + (int)SnakeGame.HighScore, new Vector2(898, 30), Color.Black, .1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "HIGH SCORE: " + (int)SnakeGame.HighScore, new Vector2(902, 34), Color.Black, .1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "HIGH SCORE: " + (int)SnakeGame.HighScore, new Vector2(902, 30), Color.Black, .1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "HIGH SCORE: " + (int)SnakeGame.HighScore, new Vector2(898, 34), Color.Black, .1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            if (dying)
            {
                Color col = new Color(SnakeGame.Random.Next(256), SnakeGame.Random.Next(256), SnakeGame.Random.Next(256));
                spriteBatch.DrawString(SnakeGame.FONT, "HIGH SCORE: " + (int)SnakeGame.HighScore, new Vector2(900, 32), (distanceMoved >= SnakeGame.HighScore ? col : Color.White), .1f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
                spriteBatch.DrawString(SnakeGame.FONT, "DISTANCE: " + (int)distanceMoved, new Vector2(300, 256), col, -.1f, Vector2.Zero, 2f, SpriteEffects.None, 1f);
                return;
            }
            spriteBatch.DrawString(SnakeGame.FONT, "HIGH SCORE: " + (int)SnakeGame.HighScore, new Vector2(900, 32), Color.White, .1f, Vector2.Zero, 1f, SpriteEffects.None, 1f);

            spriteBatch.DrawString(SnakeGame.FONT, "DISTANCE: " + (int)distanceMoved, new Vector2(30, 62), Color.Black, -.1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "DISTANCE: " + (int)distanceMoved, new Vector2(34, 66), Color.Black, -.1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "DISTANCE: " + (int)distanceMoved, new Vector2(34, 62), Color.Black, -.1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "DISTANCE: " + (int)distanceMoved, new Vector2(30, 66), Color.Black, -.1f, Vector2.Zero, 1f, SpriteEffects.None, .9f);
            spriteBatch.DrawString(SnakeGame.FONT, "DISTANCE: " + (int)distanceMoved, new Vector2(32, 64), Color.White, -.1f, Vector2.Zero, 1f, SpriteEffects.None, 1f);

            //spriteBatch.DrawString(SnakeGame.FONT, "POS: " + Position, new Vector2(0, 100), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
            spriteBatch.Draw(SnakeGame.SNAKE, Position + new Vector2(xOffset, yOffset), null, Color.Lerp(color, tint, .5f), angle, new Vector2(64, 64), size, SpriteEffects.None, .75f);
            //spriteBatch.DrawString(SnakeGame.FONT, "SP: " + ScreenPosition, Position + new Vector2(xOffset, yOffset - 24), color, 0f, Vector2.Zero, 1f, SpriteEffects.None, .76f);
        }

        public override FloatRectangle GetBoundingBox()
        {
            return new FloatRectangle(Position.X - halfHitboxWidth, Position.Y - halfHitboxHeight, 2 * halfHitboxWidth, 2 * halfHitboxHeight);
        }

        public override void CollideWith(Entity e)
        {
            if (dying) return;
            if (e is DeathEntity)
            {
                SnakeGame.FALLSOUND.Play();
                Kill();
                currentLevel.ps.Gush(Position);
            }
            if (e is Spike || e is SawBlade)
            {
                currentLevel.ps.Gush(Position);
                SnakeGame.BLOOD.Play();
                size += damageShrinking;
            }
            if (e is Food)
            {
                float oldHalfHitboxHeight = halfHitboxHeight;
                size += foodRecharge;
                size = Math.Min(1f, size);
                Position.Y -= (halfHitboxHeight - oldHalfHitboxHeight);
                SnakeGame.EATMEAT.Play();
            }
        }

        public override void Kill()
        {
            if (distanceMoved > SnakeGame.HighScore)
                SnakeGame.HighScore = distanceMoved;
            dying = true;
        }
    }
}
